/*********************************************************************
 * Módulo 3. Tutorial de desarrollo con NME. Clase de Jugador Pcpal. 
 * Programación Multimedia y Juegos
 * Autor: David Vallejo Fernández    david.vallejo@tegnix.com
 * Autor: Carlos González Morcillo   carlos.gonzalez@tegnix.com
 *
 * You can redistribute and/or modify this file under the terms of the
 * GNU General Public License ad published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * and later version. See <http://www.gnu.org/licenses/>.
 *
 * This file is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.  
 *********************************************************************/

package graphics.sprites;

import util.ScoreBoard;
import graphics.ParticleSource;

import aze.display.TileClip;
import aze.display.TileLayer;
import nme.events.KeyboardEvent;
import nme.events.MouseEvent;
import nme.ui.Keyboard;
import nme.geom.Point;

// Estados del jugador =============================================
enum PState {
  Sstatic;
  Sforward;
  Sback;
}

class Player {
  var _root:TileLayer;              // Capa pcpal. de despliegue
  var _scoreBoard:ScoreBoard;       // Puntuación
  var _x:Float;  var _y:Float;      // Posición del jugador
  var _hashState:Hash<Int>;         // Id de estados del jugador
  var _vStateClip:Array<TileClip>;  // Animaciones de cada estado
  var _cState:PState;               // Estado actual (currentState)
  var _vPrize:Array<NonPlayer>;     // Array de Premios (estrellas)
  var _vEnemy:Array<NonPlayer>;     // Array de Enemigos
  var _mouseX:Float;                // Posición del Ratón
  var _mouseY:Float;

  var _particlesDie:ParticleSource; // Partículas (choque Enemigo)

  inline static var NFRAMESCSTATE:Int = 50;   // Frames para Sstatic
  inline static var SPRITESIZE:Int = 64;      // Tamaño del jugador

  // Constructor =====================================================
  public function new(layer:TileLayer, id:String, sb:ScoreBoard, 
		      vPrize:Array<NonPlayer>, 
		      vEnemy:Array<NonPlayer>):Void {
    _root = layer; _scoreBoard = sb;
    _x = 200; _y = 200; _mouseX = _x; _mouseY = _y;
    _vPrize = vPrize; _vEnemy = vEnemy;
    _vStateClip = new Array<TileClip>();
    _hashState = new Hash<Int>();
    _cState = Sstatic;

    var i = 0;
    // Carga automática de animaciones de cada estado
    for (value in Type.getEnumConstructs(PState)) {
      var sClip = new TileClip(id + "-" + value);
      _root.addChild(sClip);
      _vStateClip.push(sClip);
      _hashState.set(value, i);
      i++;
    }

    _particlesDie = new ParticleSource("smoke", _root, _x, _y, Radial);
    updateVisibleClip();
  }

  // Trabajo con Clips ===============================================
  function getClipIndex(id:PState):Int {
    if (_hashState.exists(Std.string(id))) 
      return (_hashState.get(Std.string(id)));
    return -1;
  }

  function updateVisibleClip():Void {
    for (elem in _vStateClip) elem.visible = false;
    _vStateClip[getClipIndex(_cState)].visible = true;
  }

  // checkCollision ==================================================
  // Comprueba si el jugador choca con un objeto NonPlayer
  function checkCollision(e:NonPlayer):Bool {
    if (Math.abs(_x - e.x) < (e.width / 2.0)) { 
      if (Math.abs(_y - e.y) < (e.height / 2.0)) return true;
    }
    return false;
  }

  // checkCollisionArray  =============================================
  // Recorre el array de NonPlayer comprobando si el jugador choca con
  //  cada objeto
  function checkCollisionArray(v:Array<NonPlayer>):Int {
    var i = 0;
    for (e in v) {
      if (checkCollision(e)) {    // Si hay choque
	v.remove(e);              // Eliminamos el objeto
	_root.removeChild(e);
	// Si el objeto es un enemigo, creamos partículas de humo
	var straux = Type.getClassName(Type.getClass(e));
	if (straux.indexOf("Enemy") > 0) 
	  _particlesDie.addParticles(40);
	e.removeChildObjects();  // Eliminamos sus objetos hijo
	i++;
      }
    }
    return i;
  }

  // Update ==========================================================
  function updateFromMousePosition():Void {
    var v = new Point(_mouseX - _x, _mouseY - _y);
    // Actualizamos posición del objeto (más rápido si vamos adelante)
    if (Math.abs(v.length) > 0.3) {
      if (v.x > 0) _x += v.x * 0.05;    
      else _x += v.x * 0.02;
      _y += v.y * 0.05;
      if (v.x > 0) _cState = Sforward; else _cState = Sback;
    }
    else {
      _cState = Sstatic;
    }
  }

  function updateParticles(ps: ParticleSource, w:Int, h:Int, eTime:Int) {
    ps.setPosition(_x,_y);
    ps.update(w, h, eTime);
  }

  public function update(w:Int, h:Int, eTime:Int):Void {
    updateFromMousePosition();
    updateVisibleClip();
    updateParticles(_particlesDie, w, h, eTime);

    _vStateClip[getClipIndex(_cState)].x = _x;
    _vStateClip[getClipIndex(_cState)].y = _y;

    var nprize = checkCollisionArray(_vPrize);
    _scoreBoard.update(nprize);
    var nenemy = checkCollisionArray(_vEnemy);
    _scoreBoard.update(nenemy * -2);
  }

  // Events ==========================================================
  public function onKeyPressed(event:KeyboardEvent):Void {

  }

  public function onMouseMove(event:MouseEvent):Void {
    _mouseX = event.localX; _mouseY = event.localY;
  }

}